#include "aga.h"
#include <stdio.h>
#include <string.h>

static FILE *fp = NULL;
static FILE *fpdump = NULL;



void log_ini(GeneticData * data, const char *fn)
{
	if (!strcmp(fn, "stdout"))
		fp = stdout;
	else if (!strcmp(fn, "stderr"))
		fp = stderr;
	else
		fp = fopen(fn, "w+");
	if (!fp)
		fp = stderr;
	int i;
	for (i = 0; i < data->configuration.size - 1; i++) {
		fprintf(fp, "%s;", data->configuration.table[i].identifier);
	}
	fprintf(fp, "%s\n", data->configuration.table[i].identifier);
	for (i = 0; i < data->configuration.size; i++) {
		switch (data->configuration.table[i].type) {
		case integer:
			fprintf(fp, "%d", *((int *)data->configuration.table[i].reference));
			break;
		case long_int:
			fprintf(fp, "%ld",
			        *((long *)data->configuration.table[i].
			          reference));
			break;
		case unsigned_int:
			fprintf(fp, "%u",
			        *((unsigned *)data->configuration.table[i].
			          reference));
			break;
		case floating_point:
			fprintf(fp, "%f",
			        *((double *)data->configuration.table[i].
			          reference));
			break;
		case boolean:
			fprintf(fp, "%i",
			        (int)*((bool *) data->configuration.table[i].
			               reference));
			break;
		case chars_string:
			fprintf(fp, "%s",
			        (char *)data->configuration.table[i].reference);
			break;
			/*default:
			   break; */
		}
		if (i == data->configuration.size - 1) {
			fprintf(fp, "\n\n");
		} else {
			fprintf(fp, ";");
		}
	}

	fprintf(fp, "fase;generazione;best mos;"
	        "fittest fitness;fittest mos;fittest tos;"
	        "median fitness;median mos;median tos;"
	        "worst fitness;worst mos;worst tos;"
	        "fitness eval;ls found best mos;mutation;time (clock); time (difftime)"
	        ";deltaMOS;deltaTOS;deltaNEW;deltaCOM;deltaIOS"
	        ";delta1MOS;delta1TOS;delta1NEW;delta1COM;delta1IOS"
	        "\n");
}

void log_fini(GeneticData * data)
{
	if (fp && fp != stderr && fp != stdout)
		fclose(fp);
}

void log_on_file(GeneticData * data)
{
	Ranking *the_best = &(data->People[0].Score);
	Ranking *comparison_ind = &(data->People[(int)(data->FirstParent * data->NumIndividuals)].Score);
	Ranking *the_worst = &(data->People[data->NumIndividuals - 1].Score);

	if (data->CurrentPhase < 0) {
		fprintf(fp,
		        "%4d;%4d;%4d;%9.7f;%4d;%4d;%9.7f;%4d;%4d;%9.7f;%4d;%4d;%8ld;%1d;%7.5f;%9.7f;%f"
		        /*
		         			";%4d;%4d;%4d;%4d;%4d" // DeltaMOS, DeltaTOS...
		        			";%4d;%4d;%4d;%4d;%4d" // DeltaMOS, Delta1TOS...
		        */
		        "\n",
		        data->CurrentPhase, data->CurrentGeneration,
		        data->BestMosInd.Score.measure[MOS], the_best->score,
		        the_best->measure[MOS], the_best->measure[TOS], 0., 0,
		        0, 0., 0, 0, (data->stat).fitness_evaluations,
		        data->stat.ls_found_opt,
		        data->ProbMutation,
		        (double)(clock() -
		                 (data->stat).elaps[WHOLE_ALG].start) /
		        CLOCKS_PER_SEC, difftime(time(NULL), data->beginTime)
		        /*
		         			// Distanze fra individui
		        			, comparison_ind->measure[MOS] - the_best->measure[MOS]
		        			, comparison_ind->measure[TOS] - the_best->measure[TOS]
		        			, comparison_ind->measure[NEW] - the_best->measure[NEW]
		        			, comparison_ind->measure[COM] - the_best->measure[COM]
		        			, comparison_ind->measure[IOS] - the_best->measure[IOS]
		        			, the_worst->measure[MOS] - comparison_ind->measure[MOS]
		        			, the_worst->measure[TOS] - comparison_ind->measure[TOS]
		        			, the_worst->measure[NEW] - comparison_ind->measure[NEW]
		        			, the_worst->measure[COM] - comparison_ind->measure[COM]
		        			, the_worst->measure[IOS] - comparison_ind->measure[IOS]
		        */
		       );
		// fflush(NULL);

	} else {
		Ranking *the_median =
		    &(data->People[data->NumIndividuals / 2].Score);
		Ranking *the_worst =
		    &(data->People[data->NumIndividuals - 1].Score);

		fprintf(fp,
		        "%4d;%4d;%4d;%9.7f;%4d;%4d;%9.7f;%4d;%4d;%9.7f;%4d;%4d;%8ld;%1d;%7.5f;%9.7f;%f"
		        ";%4d;%4d;%4d;%4d;%4d" // DeltaMOS, DeltaTOS...
		        ";%4d;%4d;%4d;%4d;%4d" // DeltaMOS, Delta1TOS...
		        "\n",
		        data->CurrentPhase, data->CurrentGeneration,
		        data->BestMosInd.Score.measure[MOS], the_best->score,
		        the_best->measure[MOS], the_best->measure[TOS],
		        the_median->score, the_median->measure[MOS],
		        the_median->measure[TOS], the_worst->score,
		        the_worst->measure[MOS], the_worst->measure[TOS],
		        data->stat.fitness_evaluations, data->stat.ls_found_opt,
		        data->ProbMutation,
		        (double)(clock() -
		                 data->stat.elaps[WHOLE_ALG].start) /
		        CLOCKS_PER_SEC, difftime(time(NULL), data->beginTime)
		        // Distanze fra individui
		        , comparison_ind->measure[MOS] - the_best->measure[MOS]
		        , comparison_ind->measure[TOS] - the_best->measure[TOS]
		        , comparison_ind->measure[NEW] - the_best->measure[NEW]
		        , comparison_ind->measure[COM] - the_best->measure[COM]
		        , comparison_ind->measure[IOS] - the_best->measure[IOS]
		        , the_worst->measure[MOS] - comparison_ind->measure[MOS]
		        , the_worst->measure[TOS] - comparison_ind->measure[TOS]
		        , the_worst->measure[NEW] - comparison_ind->measure[NEW]
		        , the_worst->measure[COM] - comparison_ind->measure[COM]
		        , the_worst->measure[IOS] - comparison_ind->measure[IOS]
		       );
#ifdef VERBOSE_DEBUG
		fprintf(stderr,
		        "Gen: %4d   Phase: %1d   Best: %9.7f (%3d)   Median: %9.7f (%3d)   Worst: %9.7f (%3d)   BM: %3d   Gen/LS: %1d   Time: %8.3f(s)\n",
		        data->CurrentGeneration, data->CurrentPhase,
		        the_best->score, the_best->measure[MOS],
		        the_median->score, the_median->measure[MOS],
		        the_worst->score, the_worst->measure[MOS],
		        data->BestMosInd.Score.measure[MOS],
		        data->stat.ls_found_opt,
		        (double)(clock() -
		                 data->stat.elaps[WHOLE_ALG].start) /
		        CLOCKS_PER_SEC
		       );
		fflush(NULL);
#endif
	}
}

void dumpPopulation(GeneticData *data, int lastIndividual)
{
	if (fpdump == NULL) {
		fpdump = fopen("dump.csv", "w+");
		if (!fpdump)
			fpdump = stderr;
		fprintf(fpdump, "Phase;Rank;Sequence;MOS;TOS;SNEW;SCOM;IOS\n");
	}

	if (lastIndividual == 0)
		lastIndividual = data->NumIndividuals;

	for (int i = 0; i < lastIndividual; i++) {
		fprintf(fpdump, "%4d;%4d;", data->CurrentPhase, i);
		for (int j = 0; j < data->NumGenes - 1; j++)
			fprintf(fpdump, "%d ", data->People[i].Sequence[j]);
		fprintf(fpdump, "%d;", data->People[i].Sequence[data->NumGenes - 1]);
		for (int k = 0; k < parameters - 1; k++)
			fprintf (fpdump, "%d;", data->People[i].Score.measure[k]);
		fprintf (fpdump, "%d\n", data->People[i].Score.measure[parameters-1]);
	}
}

